package cn.minimelon.api.service.module.utils;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import cn.minimelon.api.domain.enums.DataTypeEnum;
import cn.minimelon.api.domain.enums.SwTypeEnum;
import cn.minimelon.api.domain.module.vo.DataModelVO;
import cn.minimelon.api.domain.module.vo.DataPropVO;
import cn.minimelon.api.exception.ServiceException;
import cn.minimelon.api.utils.MelonUtils;
import org.noear.snack.ONode;
import org.noear.solon.Solon;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * 模型建表校验工具
 */
public class ModelUtil {
    private static final ModelUtil INSTANCE = new ModelUtil();

    private final Map<String, List<String>> typeMap = new HashMap<>();

    private final List<String> hideList = new ArrayList<>();

    // 私有构造函数，防止外部直接创建实例
    private ModelUtil() {
        int strCol = Solon.cfg().getInt("melon.module.strCol", 10);
        List<String> strList = new ArrayList<>();
        for (int i = 0; i < strCol; i++) {
            strList.add(String.format("c%02d", i + 1));
        }
        typeMap.put(DataTypeEnum.TEXT.getVal(), strList);

        int numCol = Solon.cfg().getInt("melon.module.numCol", 5);
        List<String> numList = new ArrayList<>();
        for (int i = 0; i < numCol; i++) {
            numList.add(String.format("n%02d", i + 1));
        }
        typeMap.put(DataTypeEnum.NUMB.getVal(), numList);

        int dateCol = Solon.cfg().getInt("melon.module.dateCol", 5);
        List<String> dateList = new ArrayList<>();
        for (int i = 0; i < dateCol; i++) {
            dateList.add(String.format("d%02d", i + 1));
        }
        typeMap.put(DataTypeEnum.DATE.getVal(), dateList);

        int hideCol = Solon.cfg().getInt("melon.module.hideCol", 100);
        for (int i = 0; i < hideCol; i++) {
            hideList.add(String.format("h%03d", i + 1));
        }
    }

    // 公有的静态方法，用于获取单例对象
    public static ModelUtil getInstance() {
        return INSTANCE;
    }

    // 分配索引列，分配后台码
    public List<DataPropVO> distributeHideCol(List<DataPropVO> propList) {
        List<DataPropVO> updateList = new ArrayList<>();
        for (DataPropVO prop : propList) {
            if (StrUtil.isNotEmpty(prop.getHideCode())) {
                hideList.remove(prop.getHideCode());
            }
            if (StrUtil.equals(prop.getQuickSw(), SwTypeEnum.NO.val()) && StrUtil.isNotEmpty(prop.getCode())) {
                prop.setColCode(null);
                updateList.add(prop);
            }
            if (!StrUtil.equals(prop.getDataType(), DataTypeEnum.FILE.getVal())) {
                if (StrUtil.isNotEmpty(prop.getColCode())) {
                    List<String> colList = typeMap.get(prop.getDataType());
                    colList.remove(prop.getColCode());
                }
            }
        }
        for (DataPropVO prop : propList) {
            if (StrUtil.isEmpty(prop.getHideCode())) {
                String hideCode = hideList.remove(0);
                prop.setHideCode(hideCode);
                updateList.add(prop);
            }
            if (StrUtil.equals(prop.getQuickSw(), SwTypeEnum.YES.val())
                    && !StrUtil.equals(prop.getDataType(), DataTypeEnum.FILE.getVal())
                    && StrUtil.isEmpty(prop.getColCode())) {
                List<String> colList = typeMap.get(prop.getDataType());
                String colCode = colList.remove(0);
                prop.setColCode(colCode);
                updateList.add(prop);
            }
        }
        // 按ID去重复
        return updateList.stream()
                .filter(MelonUtils.distinct(DataPropVO::getUid))
                .collect(Collectors.toList());
    }

    // 校验索引列
    public void validIdxCol(List<DataPropVO> originList) {
        List<DataPropVO> propList = originList.stream()
                .filter(it -> !StrUtil.startWith(it.getHideCode(), "sys"))
                .collect(Collectors.toList());
        if (CollUtil.isEmpty(propList)) {
            throw new ServiceException("模型不允许无属性提交");
        }
        int hideCol = Solon.cfg().getInt("melon.module.hideCol", 100);
        if (CollUtil.size(propList) > hideCol) {
            throw new ServiceException("属性总数不允许超过上限");
        }
        Map<String, List<DataPropVO>> groups = propList.stream()
                .filter(it -> StrUtil.equals(it.getQuickSw(), SwTypeEnum.YES.val()))
                .collect(Collectors.groupingBy(DataPropVO::getDataType));
        List<DataPropVO> textGroup = groups.get(DataTypeEnum.TEXT.getVal());
        int strCol = Solon.cfg().getInt("melon.module.strCol", 10);
        if (CollUtil.size(textGroup) > strCol) {
            throw new ServiceException("字符属性开启快捷搜索超过上限");
        }
        List<DataPropVO> dateGroup = groups.get(DataTypeEnum.DATE.getVal());
        if (CollUtil.size(dateGroup) > strCol) {
            throw new ServiceException("日期属性开启快捷搜索超过上限");
        }
        List<DataPropVO> numbGroup = groups.get(DataTypeEnum.NUMB.getVal());
        if (CollUtil.size(numbGroup) > strCol) {
            throw new ServiceException("数值属性开启快捷搜索超过上限");
        }
    }

    public static void buildJsonInfo(DataModelVO res) {
        if (StrUtil.isNotEmpty(res.getExtJson())) {
            res.setExt(ONode.deserialize(res.getExtJson(), Map.class));
            res.setExtJson(null);
        } else {
            res.setExt(new HashMap<>());
        }
        if (StrUtil.isNotEmpty(res.getSwtJson())) {
            res.setSwt(ONode.deserialize(res.getSwtJson(), Map.class));
            res.setSwtJson(null);
        } else {
            res.setSwt(new HashMap<>());
        }
    }
}
